/*
 * janela.cpp
 *
 *  Created on: 11/11/2011
 *      Author: felipe
 */

#include "janela.h"

Window::Window(const int &width, const int &height) :
	width_(width), height_(height),babuRight_(0),babuLeft_(0)
{
	if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
	{
		cout << "Erro de inicialização do SDL\n";
		exit(1);
	}
	screen_ = SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE);
	if (screen_ == NULL)
	{
		cout << "Erro de inicialização do SDL\n";
		exit(1);
	}
	SDL_WM_SetCaption("Babuinos", "PPC");
	statistic_.pos.x_ = (width_ - statistic_.w) /2;
	statistic_.pos.y_ = 0;
	Image *bac = new Image("fundoPreto.jpg",Point2d(statistic_.pos.x_, statistic_.pos.y_));
	back_ = NULL;
	statistic_.back = bac->getImg();
	init_semaphore(&monMutex,1);
	SDL_SetAlpha( statistic_.back, SDL_SRCALPHA, statistic_.alpha );
}

Window::~Window()
{
	SDL_Quit();
}

void Window::update()
{
	if (SDL_Flip(screen_) == -1)
	{
		cout << "Erro de atualização do SDL\n";
		exit(1);
	}
}




bool Window::checkBridge(const int &dir,const int &pos)
{
	int i,j = 0;
	bool thereOppsite = false;
	/*Se o macaco já esta ponte, acesso permitido*/
	if (monksInb_[pos]->getPos().x_ > INIT_BRIDGE_LEFT && monksInb_[pos]->getPos().x_ < INIT_BRIDGE_RIGHT)
	{
		return false;
	}
	for( i = 0; i < monksInb_.size(); i++)
	{
		/*checa se existe algum macaco do lado oposto que ja está na ponte, nesse caso acesso negado*/
		if(monksInb_[i]->getDir() == MLEFT)
		{
			if(monksInb_[i]->getDir() == dir && monksInb_[i]->getPos().x_ > INIT_BRIDGE_LEFT)
			{
				return true;
			}
		}
		else
		{
			if(monksInb_[i]->getDir() == dir && monksInb_[i]->getPos().x_ < INIT_BRIDGE_RIGHT)
			{
				return true;
			}
		}
		/*checa se existe algum macaco do lado oposto na frente na fila*/
		if (i < pos)
		{
			if (monksInb_[pos]->getDir() != monksInb_[i]->getDir())
			{
				thereOppsite = true;
			}
		}
	}
	if(thereOppsite)/*se existe checa se 3 macacos na mesma direação ja atravessaram se sim, acesso negado*/
	{
		if(monksInb_[pos]->getDir() == MRIGHT && babuRight_ >= 3)
		{
			return true;
		}
		if(babuLeft_ >= 3)
		{
			return true;
		}
	}
	/*Caso não exista um macaco contrário, zero o contador da sua direção, se existir incrementa +1*/
	if(monksInb_[pos]->getDir() == MRIGHT)
	{
		if(!thereOppsite && babuRight_ >= 3)
		{
			babuRight_ = 0;
		}
		else
		{
			babuRight_++;
		}
	}
	else
	{
		if(!thereOppsite && babuLeft_ >= 3)
		{
			babuLeft_ = 0;
		}
		else
		{
			babuLeft_++;
		}
	}
	/*acesso permitido*/
	return false;
}

void Window::monkB()
{
	unsigned int i;
	down(&monMutex);
	for (i = 0; i < monksInb_.size(); i++)
	{
		if(monksInb_[i])
		{

			if(monksInb_[i]->getDir() == MRIGHT)
			{
				/*Se o método permiti acesso a ponte*/
				if(!checkBridge(MLEFT,i))
				{

					monksInb_[i]->move(Point2d(monksInb_[i]->getPos().x_ - TRAVEL_BRIDGE/(FRAMES_PER_SECOND*3),monksInb_[i]->getPos().y_));
					/*Se atravessou a ponte*/
					if(monksInb_[i]->getPos().x_ <= INIT_BRIDGE_LEFT)
					{
						/*mova do vetor monksInb para monksInr*/
						monksInr_.push_back(new Monkey(monksInb_[i]->getId()));
						monksInr_[monksInr_.size()-1]->setDir(monksInb_[i]->getDir());
						monksInr_[monksInr_.size()-1]->setFrame(monksInb_[i]->getFrame());
						monksInr_[monksInr_.size()-1]->move(monksInb_[i]->getPos());
						monksInb_.erase(monksInb_.begin() + i);
						i--;
					}
					else
					{
						monksInb_[i]->show(screen_);

					}
					continue;
				}
			}
			if(monksInb_[i]->getDir() == MLEFT)
			{
				if(!checkBridge(MRIGHT,i))
				{

					monksInb_[i]->move(Point2d(monksInb_[i]->getPos().x_ + 250/(FRAMES_PER_SECOND*3) ,monksInb_[i]->getPos().y_));
					if(monksInb_[i]->getPos().x_ >= 500)
					{
						monksInr_.push_back(new Monkey(monksInb_[i]->getId()));
						monksInr_[monksInr_.size()-1]->setDir(monksInb_[i]->getDir());
						monksInr_[monksInr_.size()-1]->setFrame(monksInb_[i]->getFrame());
						monksInr_[monksInr_.size()-1]->move(monksInb_[i]->getPos());
						monksInb_.erase(monksInb_.begin() + i);
						i--;
					}
					else
					{
						monksInb_[i]->show(screen_);

					}
					continue;
				}
			}
			monksInb_[i]->show(screen_);
		}



	}
	up(&monMutex);
}




void Window::monkQ()
{
	unsigned int i;
	for (i = 0; i < monksInq_.size(); i++)
	{
		down(&monMutex);
		if(monksInq_[i] != NULL)
		{
			/*Se não chegou na ponte ainda*/
			if(monksInq_[i]->getDir() == MRIGHT && monksInq_[i]->getPos().x_ > INIT_BRIDGE_RIGHT)
			{
				/*caso o movimento ultrapasse a ponta da ponte, a posição deve ser setada para a ponta da ponte*/
				if (monksInq_[i]->getPos().x_ - TRAVEL_RIGHT/FRAMES_PER_SECOND < INIT_BRIDGE_RIGHT)
				{
					monksInq_[i]->move(Point2d(INIT_BRIDGE_RIGHT,monksInq_[i]->getPos().y_));
				}
				else
				{
					monksInq_[i]->move(Point2d(monksInq_[i]->getPos().x_ - 300/FRAMES_PER_SECOND,monksInq_[i]->getPos().y_));
				}
			}
			else if(monksInq_[i]->getDir() == MLEFT && monksInq_[i]->getPos().x_ < INIT_BRIDGE_LEFT)
			{
				if (monksInq_[i]->getPos().x_ + TRAVEL_LEFT/FRAMES_PER_SECOND > INIT_BRIDGE_LEFT)
				{
					monksInq_[i]->move(Point2d(INIT_BRIDGE_LEFT,monksInq_[i]->getPos().y_));
				}
				else
				{
					monksInq_[i]->move(Point2d(monksInq_[i]->getPos().x_ + TRAVEL_LEFT/FRAMES_PER_SECOND,monksInq_[i]->getPos().y_));
				}

			}
			monksInq_[i]->show(screen_);
		}
		up(&monMutex);
	}
}

void Window::monkR()
{
	unsigned int i;
	bool ok;
	for (i = 0; i < monksInr_.size(); i++)
	{
		ok = true;
		if(monksInr_[i]->getDir() == MRIGHT)
		{
			monksInr_[i]->move(Point2d(monksInr_[i]->getPos().x_ - VEL,monksInr_[i]->getPos().y_));
			if(monksInr_[i]->getPos().x_ <= -30) /*-30 posição final do macaco direito*/
			{
				monksInr_.erase(monksInr_.begin() + i);
				i--;
				ok = false;
			}
		}
		else if(monksInr_[i]->getDir() == MLEFT)
		{
			monksInr_[i]->move(Point2d(monksInr_[i]->getPos().x_ + VEL,monksInr_[i]->getPos().y_));
			if(monksInr_[i]->getPos().x_ >= 800)/*posição final do macaco esquerdo*/
			{
				monksInr_.erase(monksInr_.begin() + i);
				i--;
				ok = false;
			}
		}
		if(ok)/*evita que macacos com valor i inválido seja acessado*/
		{
			monksInr_[i]->show(screen_);
		}
	}
}

void Window::waitFps()
{
	if( fps.getTicks() < 1000 / FRAMES_PER_SECOND )
	{
		SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.getTicks() );
	}
}

void Window::results() {
	char texto[MAX_CHAR];
	char texto2[MAX_CHAR];
	char texto3[MAX_CHAR];
	char texto4[MAX_CHAR];

	sprintf(texto, "Babuinos da esquerda: %d", statistic_.babusEsq);

	sprintf(texto2, "Babuinos da direita: %d", statistic_.totalBabus - statistic_.babusEsq);
	sprintf(texto3, "Aproveitamento da ponte: %.2lf/%.2lf: %.4lf", statistic_.busy_bright, statistic_.time_bright, statistic_.busy_bright/statistic_.time_bright);
	sprintf(texto4, "Tempo medio de espera: %.4lf", statistic_.m_wait);

	Text text(texto,"myFont.ttf", 255, 255, 255,20);
	Text text2(texto2,"myFont.ttf", 255, 255, 255,20);
	Text text3(texto3,"myFont.ttf", 255, 255, 255,20);
	Text text4(texto4,"myFont.ttf", 255, 255, 255,20);


	cout.flush();

	Point2d pos( (width_ - text.width()) /2,(height_/2 - 5*text.height() - statistic_.h )/2 + statistic_.down);
	Point2d pos2( (width_ - text2.width()) /2,(height_/2 - 10*text2.height() - statistic_.h )/2 + statistic_.down);
	Point2d pos3( (width_ - text3.width()) /2,(height_/2 - 15*text3.height() - statistic_.h )/2 + statistic_.down);
	Point2d pos4( (width_ - text4.width()) /2,(height_/2 - 20*text4.height() - statistic_.h )/2 + statistic_.down);

	text.setPos(pos);
	text2.setPos(pos2);
	text3.setPos(pos3);
	text4.setPos(pos4);

	printText(text);
	printText(text2);
	printText(text3);
	printText(text4);


}

void Window::loop()
{
	bool quit = false;

	appBackground("bri.jpg");
	struct timeval tv;
	fd_set readfds;
	tv.tv_sec = 0;
	tv.tv_usec = 10000;
	update();
	char cmdc[20],dirc[20];
	string cmd,dir;
	int id;
	bool run = true;
	while (quit == false)
	{
		//cout<<"loop\n";
		fps.start();
		while (SDL_PollEvent(&event_))
		{
			if (event_.type == SDL_QUIT)
			{
				quit = true;
			}
		}
		if(run)
		{
			/*Controle do tempo de leitura dos comandos*/
			FD_ZERO(&readfds);
			FD_SET(STDIN, &readfds);
			select(1, &readfds, NULL, NULL, &tv);
			if (FD_ISSET(STDIN, &readfds))
			{
				memset(cmdc,'\0',20);
				memset(dirc,'\0',20);
				scanf("%s %d %s\n",cmdc,&id,dirc);
				cmd = cmdc;
				dir = dirc;
				cout<<cmd<<id<<dirc<<endl;
				cout.flush();
				if (cmd == "Chegando")
				{/*Chegada de um macaco*/

					if(dir == "Direito")
					{
						/*cria um macaco vindo na direção direita*/
						monksInq_.push_back(new Monkey(id));
						monksInq_[monksInq_.size()-1]->setDir(MRIGHT);
						monksInq_[monksInq_.size()-1]->move(Point2d(width_,height_ /2 - MONKEY_HEIGHT + 52));

					}
					else
					{
						/*cria um macaco vindo na direção esquerda*/
						monksInq_.push_back(new Monkey(id));
						monksInq_[monksInq_.size()-1]->setDir(MLEFT);
						monksInq_[monksInq_.size()-1]->setFrame(5);
						monksInq_[monksInq_.size()-1]->move(Point2d(0,height_ /2 - MONKEY_HEIGHT + 52));

					}
				}
				else if (cmd == "Atravessando")
				{
					/*Trasfere o macaco de monksInq para monksInb*/
					monksInb_.push_back(new Monkey(monksInq_[id-1]->getId()));
					monksInb_[monksInb_.size()-1]->setDir(monksInq_[id-1]->getDir());
					monksInb_[monksInb_.size()-1]->setFrame(monksInq_[id-1]->getFrame());
					monksInb_[monksInb_.size()-1]->move(monksInq_[id-1]->getPos());
					down(&monMutex);
					delete monksInq_[id-1];
					monksInq_[id-1] = NULL;
					up(&monMutex);
				}
				else if (cmd == "Atravessou")
				{
				}
				else if (cmd == "end")
				{
					scanf("%lf %lf %lf\n",&statistic_.m_wait, &statistic_.busy_bright, &statistic_.time_bright);
					cout<<statistic_.m_wait<<' '<<statistic_.busy_bright<<' '<<statistic_.busy_bright<<endl;
					cout.flush();
					statistic_.ending = true;
					statistic_.babusEsq	= id;
					statistic_.totalBabus = atoi(dirc);
					statistic_.setClip(0, statistic_.h - statistic_.down, statistic_.w, statistic_.down);
					run = false;
				}
			}


		}
		if (statistic_.ending) {
			if (statistic_.clip.y > 0) {
				statistic_.setClip(0, statistic_.h - statistic_.down, statistic_.w, statistic_.down);
				apply_surface(statistic_.pos.x_, statistic_.pos.y_, statistic_.back, &statistic_.clip);
			} else  if (statistic_.down < 450){
				statistic_.pos.y_ += 1;
				apply_surface(statistic_.pos.x_, statistic_.pos.y_, statistic_.back);
			} else {
				apply_surface(statistic_.pos.x_, statistic_.pos.y_, statistic_.back);
			}
			if (statistic_.down < 450) {
				statistic_.down += 1;
			}

			results();
		}
		monkB();
		monkQ();
		monkR();
		update();
		clean();
		waitFps();
	}
}

void Window::clean()
{
	if (back_)
	{
		SDL_BlitSurface(back_, NULL, screen_, NULL);
	}

}

void Window::apply_surface( int x, int y, SDL_Surface* source, SDL_Rect* clip)
{
    //Holds offsets
    SDL_Rect offset;

    //Get offsets
    offset.x = x;
    offset.y = y;

    //Blit
    SDL_BlitSurface( source, clip, screen_, &offset );
	//update();
}

void Window::appBackground(const string &background)
{
	if(back_)
	{
		SDL_FreeSurface(back_);
	}
	Image *bac = new Image(background,Point2d(0,0));
	back_ = bac->getImg();
	SDL_Rect offset;
	offset.x = 0;
	offset.y = 0;
	SDL_BlitSurface(back_, &offset, screen_, NULL);

}


void Window::printText(const Text &text)
{
	SDL_Rect offset;
	Point2d pos = text.getPos();
	offset.x = pos.x_;
	offset.y = pos.y_;
	SDL_BlitSurface(text.getTextScreen(), NULL, screen_, &offset);
	//update();
}


